<template>    
    <h4>选择分离轨道</h4> 
    <div class="stems" v-loading="loading">
      <div class="instruments">
        <div class="instrument-item-wrapper" @click="()=> {if(!loading) vocalChecked = !vocalChecked}">
          <div class="instrument-item">
            <img src="@/assets/vocal.svg"/>
            <span>人声</span>
          </div>
          <el-icon class="tag" v-if="vocalChecked"><SuccessFilled /></el-icon>
        </div>
        <div class="instrument-item-wrapper" @click="()=> {if(!loading) drumsetChecked = !drumsetChecked}">
          <div class="instrument-item">
            <img src="@/assets/drumset.svg"/>
            <span>鼓组</span>
          </div>
          <el-icon class="tag" v-if="drumsetChecked"><SuccessFilled /></el-icon>
        </div>
        <div class="instrument-item-wrapper" @click="()=>{if(!loading) bassChecked = !bassChecked}">
          <div class="instrument-item">
            <img src="@/assets/bass.svg"/>
            <span>贝斯</span>
          </div>
          <el-icon class="tag" v-if="bassChecked"><SuccessFilled /></el-icon>
        </div>
        <div class="instrument-item-wrapper" @click="()=>{if(!loading) pianoChecked = !pianoChecked}">
          <div class="instrument-item">
            <img src="@/assets/piano.svg"/>
            <span>钢琴</span>
          </div>
          <el-icon class="tag" v-if="pianoChecked"><SuccessFilled /></el-icon>
        </div>
      </div>
    </div>    
    <h4>保存到</h4>
    <div style="width:400px">
      <el-input
        v-model="saveToFolder"
        :disabled="loading"    
        placeholder="请选择保存轨道音频的文件夹位置"
      >
        <template #append>
          <el-button @click="browerSaveFolder">浏览</el-button>
        </template>
      </el-input>
    </div>
    <h4>添加文件</h4>
    <file-drop @fileSelected="fileSelected" :loading="loading"></file-drop>
    <span class="tips"> * 最多选择3个文件</span>
    <div class="file-list" v-for="(item,i) in files" :key="i">
      <el-progress :text-inside="true" :stroke-width="26" :percentage="item.percentage" :indeterminate="item.indeterminate" :duration="5" :status="item.status" >
        <span>{{ item?.name }}  {{item?.errorMsg}}</span>
      </el-progress>
    </div>
</template>

<script>
import FileDrop from "./FileDrop/Index.vue"
import { ElMessageBox } from 'element-plus'
import { ref } from 'vue';
export default ({
  name:"MainWindow",
  components:  {FileDrop} ,
  setup(){   

    let trackCount=2
    const vocalChecked=ref(false)
    const drumsetChecked=ref(false)
    const bassChecked=ref(false)
    const pianoChecked=ref(false)
    const saveToFolder=ref('')
    const loading=ref(false)
    let fileCount=0
    let successCount=0
    let failCount=0    
    const files=ref([])
    let handleIndex=0
    const maxHandleFile=3

    const browerSaveFolder = async () =>{
      const filePaths = await window.electronAPI.showOpenDialog({
        properties: ['openDirectory']
      })
      if(filePaths)
        saveToFolder.value = filePaths[0]
    }

    const openOutputDirectory = ()=>{
      window.electronAPI.openDirectory(saveToFolder.value)
    }  

    const showMessage = (icon,tips,title,isConfirm)=>{
      if(!isConfirm){
        ElMessageBox.alert(tips,title,{type:icon})
      }
      else
        ElMessageBox.confirm(tips,title,{confirmButtonText:'打开目录',cancelButtonText:'关闭',type:icon}).then(()=>{
          openOutputDirectory()
      }).catch(()=>{})
    }

    const showResult = ()=>{
      const isAllFailed = failCount===fileCount
      const isAllSuccess = successCount===fileCount
      let icon = 'success'
      if(isAllFailed) icon='error'
      if(!isAllSuccess) icon='warning'
      const title= isAllFailed?'分离失败':'分离完成'
      let tips='成功分离文件：'+successCount+'个，失败：'+failCount+'个'
      if(isAllSuccess)
        tips='成功分离'+successCount+'个音乐文件'
      else if(isAllFailed)
        tips='分离'+successCount+'个音乐文件失败！'
      const isConfirm = !isAllFailed
      loading.value=false
      showMessage(icon,tips,title,isConfirm)
    }    

    const filterFiles = (selectedFiles) => {
      files.value=[]
      const length=selectedFiles.length>maxHandleFile?maxHandleFile:selectedFiles.length
      for(var i=0;i<length;i++){
        const file=selectedFiles[i]
        const definedFile = {
          name:file.name,
          path:file.path,
          percentage:0,
          indeterminate:false,
          status:'',
          errorMsg:''
        }
        files.value.push(definedFile)
      }
    }

    const fileEnd = (file,isSuccess) =>{
      file.indeterminate=false
      if(isSuccess){
        successCount++
        file.status='success'
      }
      else {
        failCount++
        file.status='exception'
        file.errorMsg='分离失败！'
      }
    }

    const nextSong = () => {
      handleIndex++     
      if(handleIndex>=files.value.length){
        showResult()
      }
      else
      {
        spleetTracks()
      }
    }

    const getDeleteFiles = (input,output,tracks)=>{
      if(tracks===2) return
      let end = input.lastIndexOf('.')
      var fileName= input.substr(0,end)
      let deleteFiles = []
      let needToCombine = false
      if(!vocalChecked.value) {
        needToCombine = true
        const file = output + "\\" + fileName + "\\vocals.wav"
        deleteFiles.push(file)
      }
      if(!drumsetChecked.value) {
        needToCombine = true
        const file = output + "\\" + fileName + "\\drums.wav"
        deleteFiles.push(file)
      }
      if(!bassChecked.value) {
        needToCombine = true
        const file = output + "\\" + fileName + "\\bass.wav"
        deleteFiles.push(file)
      }
      if(!needToCombine) return
      const otherFile= output + "\\" + fileName + "\\other.wav"
      deleteFiles.push(otherFile)
      return deleteFiles
    }    

    const deleteTracks = () =>{
      const file=files.value[handleIndex]
      const deleteFiles = getDeleteFiles(file.name,saveToFolder.value,trackCount)
      if(!deleteFiles)
      {
        fileEnd(file,true)
        nextSong()
      }
      else
        window.electronAPI.deleteTracks(deleteFiles)
    }

    window.electronAPI.onDeleteTracksCallback((_event, value) => {
      const file=files.value[handleIndex]      
      const isSuccess = value.stdout!=='' 
      fileEnd(file,isSuccess)
      nextSong()
    })

    const generateRecombineScript = (input,output,tracks)=>{
      if(tracks === 2) return
      let end = input.lastIndexOf('.')
      var fileName= input.substr(0,end)
      let combineString=''
      let combineInputCount=0
      
      if(!vocalChecked.value) {
        combineInputCount++
        const vocalFile= output + "\\" + fileName + "\\vocals.wav"
        combineString+=" -i \""+vocalFile+"\""        
      }
      if(!drumsetChecked.value) {
        combineInputCount++
        const drumsFile= output + "\\" + fileName + "\\drums.wav"
        combineString+=" -i \""+drumsFile+"\""
      }
      if(!bassChecked.value) {
        combineInputCount++
        const bassFile= output + "\\" + fileName + "\\bass.wav"
        combineString+=" -i \""+bassFile+"\""
      }
      if(combineInputCount==0) return
      combineInputCount++
      const otherFile= output + "\\" + fileName + "\\other.wav"
      combineString+=" -i \""+otherFile+"\""

      let filter_a=''
      let filter_b=''
      for(let i=0;i<combineInputCount;i++){
        const volume=97+i
        filter_a+="["+i+"]volume="+combineInputCount+"["+volume+"];"
        filter_b+="["+volume+"]"
      }
      const combineCmdStr="ffmpeg.exe" + combineString +" -filter_complex "+"\"" + filter_a + filter_b + "amix=inputs=" + combineInputCount + ":duration =longest" + "\" \"" + output + "\\" + fileName + "\\accompaniment.wav\""
      return combineCmdStr
    }

    const recombineTracks = ()=>{  
     const file=files.value[handleIndex]
     const recombineCmdStr = generateRecombineScript(file.name,saveToFolder.value,trackCount)
      if(!recombineCmdStr)
      {
        fileEnd(file,true)
        nextSong()
      }
      else
        window.electronAPI.recombineTracks(recombineCmdStr)
    }

    window.electronAPI.onRecombineTracksCallback((_event, value) => {
      if(value.stdout){
        deleteTracks()
      }
      else {
        const file=files.value[handleIndex]   
        fileEnd(file,false)
        nextSong()
      }      
    })

    const generatePythonScript = (input,output,tracks) => {
      return "\"Python37_64/python.exe\" -m spleeter separate -o " + "\""+output+"\"" + " -p spleeter:"+tracks+"stems "+"\""+input+"\""
    }

    const spleetTracks = () => {

      const file=files.value[handleIndex]
      file.percentage=100
      file.indeterminate=true
      // Spleeter separete
      trackCount=2
      if(pianoChecked.value) trackCount = 5
      else if(drumsetChecked.value||bassChecked.value) trackCount=4
      const separateCmdStr = generatePythonScript(file.path,saveToFolder.value,trackCount)
      window.electronAPI.separateTracks(separateCmdStr)      
    }

    window.electronAPI.onSeparateTracksCallback((_event, value) => { 
      if(value.stdout){
        recombineTracks()
      }
      else {
        const file = files.value[handleIndex]
        fileEnd(file,false)
        nextSong()
      }
    })

    const fileSelected = (selectedFiles)=>{
      if(!vocalChecked.value&&!drumsetChecked.value&&!bassChecked.value&&!pianoChecked.value){
        showMessage('warning','请选择分离轨道','提示',false)
        return
      }      
      if(saveToFolder.value===''){
        showMessage('warning','请选择保存轨道音频的文件夹位置','提示',false)
        return
      }      
      filterFiles(selectedFiles)
      loading.value = true
      handleIndex = 0
      fileCount=files.value.length
      successCount=0
      failCount=0
      spleetTracks()
    }

    return{
      vocalChecked,drumsetChecked,bassChecked,pianoChecked,saveToFolder,browerSaveFolder,loading,files,fileSelected
    }
  }
})
</script>

<style scoped lang="scss">
h2{
  margin: 15px auto;
}
h4{
  margin: 10px auto;
}
.stems{
  display: flex;
  flex-direction: row;
  align-items: center;
  width: 400px;
}
.instruments{
  display: flex;
  flex-direction: row;
  align-items: center;
  margin:10px 0;
  .instrument-item-wrapper{
    padding: 6px 14px;
    border-radius: 4px;
    position: relative;
    cursor: pointer;
    :hover{
      color: #409eff
    }
    .instrument-item{
      display: flex;
      flex-direction: column;
      justify-content: center; 
      align-content: center;
      img{
        height: 42px;
      }
      span{
        font-size: 12px;
        text-align: center;
      }
    }
    .tag{
      position:absolute;
      top:0;
      right: 0;
      color: #67c23a;
    }
  }
  
}
.tips{
  margin: 5px;
  font-size: 12px;
  color:#a8abb2;
}
.file-list{
  width: 400px;
  margin: 10px;
}
</style>